package com.mt.restaurant.service.material.impl;

import cn.hutool.db.sql.Order;
import com.mt.restaurant.dao.material.MaterialOrderDao;
import com.mt.restaurant.dao.material.OrderMaterialRelationDao;

import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.web.base.PageDTO;
import com.mt.common.core.web.base.PageResultDTO;
import com.mt.common.core.web.base.BaseEntity;
import com.mt.common.core.web.BaseService;
import com.mt.restaurant.entity.material.Cost;
import com.mt.restaurant.entity.material.MaterialOrder;
import com.mt.restaurant.entity.material.SupplyMaterial;
import com.mt.restaurant.service.material.CostService;
import com.mt.restaurant.service.material.MaterialOrderService;
import com.mt.restaurant.service.material.SupplyMaterialService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mt.restaurant.entity.material.OrderMaterialRelation;
import com.mt.restaurant.service.material.OrderMaterialRelationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class OrderMaterialRelationServiceBean extends BaseService implements OrderMaterialRelationService {

    private static Logger logger = LogManager.getLogger();

    @Autowired
    private OrderMaterialRelationDao orderMaterialRelationDao;

    @Resource
    private RedisTemplate<String, List<OrderMaterialRelation>> redisTemplate;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    private MaterialOrderDao materialOrderDao;

    @Autowired
    private SupplyMaterialService supplyMaterialService;

    @Autowired
    private CostService costService;


    /**
     * 根据分页参数查询订单材料关系集合
     *
     * @param pageDTO 分页条件
     */
    @Override
    public PageResultDTO findOrderMaterialRelations(PageDTO pageDTO) {
        if (pageDTO.getCurrentPage() != null) {
            pageDTO.setStartIndex((pageDTO.getCurrentPage() - 1) * pageDTO.getPageSize());
        }
        //TODO:请在此校验参数的合法性
        this.validateFindOrderMaterialRelations(pageDTO);
        List<OrderMaterialRelation> orderMaterialRelationDTOS = this.orderMaterialRelationDao.findOrderMaterialRelations(pageDTO);
        Long totalCount = this.orderMaterialRelationDao.findOrderMaterialRelationTotalCount(pageDTO);

        PageResultDTO pageResultDTO = new PageResultDTO();
        pageResultDTO.setTotalCount(totalCount);
        pageResultDTO.setDatas(orderMaterialRelationDTOS);

        return pageResultDTO;
    }

    /**
     * 查询全部订单材料关系集合
     */
    @Override
    public List<OrderMaterialRelation> findAllOrderMaterialRelations() {
        return this.orderMaterialRelationDao.findAllOrderMaterialRelations();
    }

    /**
     * 查询所有订单材料关系集合(只提取ID 和 Name)
     */
    @Override
    public List<OrderMaterialRelation> findAllOrderMaterialRelationsWithIdName() {
        //TODO:请在此校验参数的合法性
        this.validateFindAllOrderMaterialRelationsWithIdName();
        return this.orderMaterialRelationDao.findAllOrderMaterialRelationsWithIdName();
    }

    /**
     * 根据名称查询订单材料关系集合(只提取ID 和 Name)
     *
     * @param orderMaterialRelationName 名称
     */
    @Override
    public List<OrderMaterialRelation> findOrderMaterialRelationsWithIdNameByName(String orderMaterialRelationName) {
        //TODO:请在此校验参数的合法性
        this.validateFindOrderMaterialRelationsWithIdNameByName(orderMaterialRelationName);
        //TODO:缓存取对应参数
        Set<String> keys = stringRedisTemplate.keys("searchData:OrderMaterialRelation_where_orderMaterialRelationName_" + orderMaterialRelationName);
        List<OrderMaterialRelation> orderMaterialRelations = new ArrayList<>();
        if (keys.isEmpty()) {
            orderMaterialRelations = this.orderMaterialRelationDao.findOrderMaterialRelationsWithIdNameByName(orderMaterialRelationName);
            redisTemplate.opsForValue().set("searchData:OrderMaterialRelation_where_orderMaterialRelationName_" + orderMaterialRelationName, orderMaterialRelations, 30, TimeUnit.DAYS);
        } else {
            orderMaterialRelations = redisTemplate.opsForValue().get("searchData:OrderMaterialRelation_where_orderMaterialRelationName_" + orderMaterialRelationName);
        }
        return orderMaterialRelations;
    }

    /**
     * 根据ID查询指定的订单材料关系(只提取ID 和 Name)
     *
     * @param orderMaterialRelationId Id
     */
    @Override
    public OrderMaterialRelation findOrderMaterialRelationsWithIdNameById(Long orderMaterialRelationId) {
        //TODO:请在此校验参数的合法性
        this.validateFindOrderMaterialRelationsWithIdNameById(orderMaterialRelationId);
        return this.orderMaterialRelationDao.findOrderMaterialRelationsWithIdNameById(orderMaterialRelationId);
    }

    /**
     * 根据ID查询指定的订单材料关系
     *
     * @param orderMaterialRelationId Id
     */
    @Override
    public OrderMaterialRelation findOrderMaterialRelation(Long orderMaterialRelationId) {
        //TODO:请在此校验参数的合法性
        this.validateFindOrderMaterialRelation(orderMaterialRelationId);
        return this.orderMaterialRelationDao.findOrderMaterialRelation(orderMaterialRelationId);
    }

    /**
     * 根据ID查询指定的订单材料关系(包含外键)
     *
     * @param orderMaterialRelationId Id
     */
    @Override
    public OrderMaterialRelation findOrderMaterialRelationWithForeignName(Long orderMaterialRelationId) {
        //TODO:请在此校验参数的合法性
        this.validateFindOrderMaterialRelationWithForeignName(orderMaterialRelationId);
        return this.orderMaterialRelationDao.findOrderMaterialRelationWithForeignName(orderMaterialRelationId);
    }

    @Override
    public List<OrderMaterialRelation> findOrderMaterialsByOrder(List<MaterialOrder> materialOrderList) {
        return this.orderMaterialRelationDao.findOrderMaterialsByOrder(materialOrderList);
    }

    @Override
    public List<OrderMaterialRelation> findOrderMaterialsByOrderId(Long materialOrderId) {
        return this.orderMaterialRelationDao.findOrderMaterialsByOrderId(materialOrderId);
    }

    /**
     * 新增订单材料关系
     *
     * @param orderMaterialRelation 实体对象
     */
    @Override
    public OrderMaterialRelation saveOrderMaterialRelation(OrderMaterialRelation orderMaterialRelation) {
        //TODO:请在此校验参数的合法性
        this.validateSaveOrderMaterialRelation(orderMaterialRelation);
        //TODO:填充公共参数
        this.setSavePulicColumns(orderMaterialRelation);
        Long rows = this.orderMaterialRelationDao.saveOrderMaterialRelation(orderMaterialRelation);
        if (rows != 1) {
            String error = "新增保存订单材料关系出错，数据库应该返回1,但返回了 " + rows;
            throw new BusinessException(error);
        }
        return orderMaterialRelation;
    }

    @Override
    public List<OrderMaterialRelation> saveOrderMaterialRelations(Long orderId, List<SupplyMaterial> supplyMaterialList) {
        if (supplyMaterialList == null) {
            return null;
        }
        List<OrderMaterialRelation> orderMaterialRelationList = new ArrayList<>();

        supplyMaterialList.forEach(value -> {
            OrderMaterialRelation orderMaterialRelation = new OrderMaterialRelation();
            this.setSavePulicColumns(orderMaterialRelation);
            orderMaterialRelation.setMaterialOrderId(orderId);
            orderMaterialRelation.setSupplyMaterialId(value.getEid());
            orderMaterialRelation.setAmount(value.getQuantity());
            orderMaterialRelation.setPrice(value.getPrice());
            Long rows = orderMaterialRelationDao.saveOrderMaterialRelation(orderMaterialRelation);
            if (rows != 1) {
                String error = "新增保存订单材料关系出错，数据库应该返回1,但返回了 " + rows;
                throw new BusinessException(error);
            }
            orderMaterialRelationList.add(orderMaterialRelation);
        });


        return orderMaterialRelationList;
    }

    private List<OrderMaterialRelation> changeOrderMaterialRelations(List<OrderMaterialRelation> orderMaterialRelationsForSave, List<OrderMaterialRelation> orderMaterialRelationsForUpdate, Long orderId) {
        List<OrderMaterialRelation> orderMaterialRelations = new ArrayList<>();

        if (orderMaterialRelationsForUpdate != null && orderMaterialRelationsForUpdate.size() != 0) {
            updateOrderMaterialRelations(orderMaterialRelationsForUpdate);
        }
        if (orderMaterialRelationsForSave != null && orderMaterialRelationsForSave.size() != 0) {
            saveOrderMaterialRelations(orderMaterialRelationsForSave, orderId);
        }

        return orderMaterialRelations;
    }

    /**
     * 批量修改
     * 对需要修改的订单材料关系列表的信息进行修改。
     *
     * @param orderMaterialRelations 需要修改的供应商材料信息
     */
    private void updateOrderMaterialRelations(List<OrderMaterialRelation> orderMaterialRelations) {
        orderMaterialRelations.forEach(orderMaterialRelation -> {
            Long rows = this.orderMaterialRelationDao.updateOrderMaterialRelation(orderMaterialRelation);
            if (rows != 1) {
                String error = "修改保存供应商材料出错，数据库应该返回" + 1 +
                        ",但返回了 " + rows + ",数据可能被删除";
                throw new BusinessException(error);
            }
        });
    }

    /**
     * 批量新增
     * 新增需要保存的订单材料关系列表。
     *
     * @param orderMaterialRelations 需要保存的供应商材料信息
     */
    private void saveOrderMaterialRelations(List<OrderMaterialRelation> orderMaterialRelations, Long orderId) {
        orderMaterialRelations.forEach(orderMaterialRelation -> {
            //填充公共参数
            this.setSavePulicColumns(orderMaterialRelation);
            orderMaterialRelation.setMaterialOrderId(orderId);
            Long rows = this.orderMaterialRelationDao.saveOrderMaterialRelation(orderMaterialRelation);
            if (rows != 1) {
                String error = "保存供应商材料出错，数据库应该返回" + 1 +
                        ",但返回了 " + rows + ",数据可能被删除";
                throw new BusinessException(error);
            }
        });
    }

    /**
     * 更新订单材料关系
     *
     * @param orderMaterialRelation 实体对象
     */
    @Override
    public OrderMaterialRelation updateOrderMaterialRelation(OrderMaterialRelation orderMaterialRelation) {
        //TODO:请在此校验参数的合法性
        this.validateUpdateOrderMaterialRelation(orderMaterialRelation);
        Long rows = this.orderMaterialRelationDao.updateOrderMaterialRelation(orderMaterialRelation);
        if (rows != 1) {
            String error = "修改保存订单材料关系出错，数据库应该返回1,但返回了 " + rows + ",数据可能被删除";
            throw new BusinessException(error);
        }
        return orderMaterialRelation;
    }

    @Override
    public OrderMaterialRelation updateOrderMaterialRelationStatus(List<OrderMaterialRelation> orderMaterialRelations) {
        //如果订单材料为空
        if (orderMaterialRelations.size() == 0 || orderMaterialRelations == null) {
            return null;
        }
        //更新订单材料状态
        Long rows = orderMaterialRelationDao.updateOrderMaterialRelationsStatus(orderMaterialRelations);
        if (rows != orderMaterialRelations.size()) {
            String error = "修改保存订单材料关系出错，数据库应该返回" + orderMaterialRelations.size() + ",但返回了 " + rows + ",数据可能被删除";
            throw new BusinessException(error);
        }
        //记录是否要退货（operate为4不退货，为6退货）
        int operate = 4;

        //记录供应原材料不合格次数
        for(OrderMaterialRelation orderMaterialRelation : orderMaterialRelations){
            if(orderMaterialRelation.getStatus().equals("不合格")){
                operate = 6;
                supplyMaterialService.updateSupplyMaterialFailuresNum(orderMaterialRelation.getSupplyMaterialId());
            }
        }
        //更新材料订单状态
        rows = materialOrderDao.updateMaterialOrdeStatus(orderMaterialRelations.get(0).getMaterialOrderId(), operate);
        if(rows!=1){
            String error = "修改保存订单材料关系出错，数据库应该返回1,但返回了 " + rows + ",数据可能被删除";
            throw new BusinessException(error);
        }
        //生成收支记录
        List<OrderMaterialRelation> orderMaterialRelationsPass = orderMaterialRelations.stream().filter(item->item.getStatus().equals("验收合格")).collect(Collectors.toList());
        Double price = orderMaterialRelationsPass.stream().collect(Collectors.summingDouble(OrderMaterialRelation::getTotalPrice));
        Cost cost = new Cost();
        cost.setTotal(price);
        cost.setStatus("支出");
        cost.setType("材料");
        costService.saveCost(cost);
        return null;
    }

    @Override
    public void returnOrderMaterial(Long orderMaterialRelationId) {
        //TODO:请在此校验参数的合法性
        this.validateDeleteOrderMaterialRelation(orderMaterialRelationId);
        Long rows = orderMaterialRelationDao.updateOrderMaterialRelationById(orderMaterialRelationId);
        if (rows != 1) {
            String error = "更新材料订单关系出错，数据可能已经被删除";
            throw new BusinessException(error);
        }
        OrderMaterialRelation orderMaterialRelation = orderMaterialRelationDao.findOrderMaterialRelation(orderMaterialRelationId);
        MaterialOrder materialOrder = this.materialOrderDao.findMaterialOrder(orderMaterialRelation.getMaterialOrderId());
        materialOrder.setPrice(materialOrder.getPrice() - orderMaterialRelation.getPrice() * orderMaterialRelation.getAmount());
        final String MATERIAL_ORDER_ID = "materialOrderId";
        final String STATUS = "status";
        Map<String, Object> filter = new HashMap<>();
        filter.put(MATERIAL_ORDER_ID, orderMaterialRelation.getMaterialOrderId());
        filter.put(STATUS, "验收合格");
        PageDTO pageDTO = PageDTO.create(filter);
        List<OrderMaterialRelation> orderMaterialRelationList = orderMaterialRelationDao.findOrderMaterialRelations(pageDTO);
        if (orderMaterialRelationList == null || orderMaterialRelationList.size() == 0) {
            materialOrder.setStatus("已退货");
        }else{
            materialOrder.setStatus("待入库");
        }
        rows = this.materialOrderDao.updateMaterialOrder(materialOrder);
        if (rows != 1) {
            String error = "修改保存材料订单出错，数据库应该返回1,但返回了 " + rows + ",数据可能被删除";
            throw new BusinessException(error);
        }

    }

    /**
     * 根据ID删除订单材料关系
     *
     * @param orderMaterialRelationId ID
     */
    @Override
    public void deleteOrderMaterialRelation(Long orderMaterialRelationId) {
        //TODO:请在此校验参数的合法性
        this.validateDeleteOrderMaterialRelation(orderMaterialRelationId);

        Map<Class<? extends BaseEntity>, EntityUsage> entityUsageMap = this.checkForeignEntity(OrderMaterialRelation.class, orderMaterialRelationId);
        if (entityUsageMap != null && entityUsageMap.size() > 0) {
            StringBuilder errors = new StringBuilder();
            errors.append("计划删除的数据正在被以下数引用\n");
            for (EntityUsage entityUsage : entityUsageMap.values()) {
                errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
                for (Map.Entry<Long, String> entry : entityUsage.getUsageIdNames().entrySet()) {
                    errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
                }
            }
            errors.append("，不能删除，请检查处理后再删除");
            throw new BusinessException(errors.toString());
        }

        Long rows = this.orderMaterialRelationDao.deleteOrderMaterialRelation(orderMaterialRelationId);
        if (rows != 1) {
            String error = "删除订单材料关系出错，数据可能已经被删除";
            throw new BusinessException(error);
        }
    }

    @Override
    public void deleteOrderMaterialRelationByOrderId(Long MaterialOrderId) {
        //TODO:请在此校验参数的合法性
        this.validateDeleteOrderMaterialRelation(MaterialOrderId);

        Map<Class<? extends BaseEntity>, EntityUsage> entityUsageMap = this.checkForeignEntity(OrderMaterialRelation.class, MaterialOrderId);
        if (entityUsageMap != null && entityUsageMap.size() > 0) {
            StringBuilder errors = new StringBuilder();
            errors.append("计划删除的数据正在被以下数引用\n");
            for (EntityUsage entityUsage : entityUsageMap.values()) {
                errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
                for (Map.Entry<Long, String> entry : entityUsage.getUsageIdNames().entrySet()) {
                    errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
                }
            }
            errors.append("，不能删除，请检查处理后再删除");
            throw new BusinessException(errors.toString());
        }

        Long rows = this.orderMaterialRelationDao.deleteOrderMaterialRelationByOrderId(MaterialOrderId);
        if (rows == 0) {
            String error = "删除订单材料关系出错，数据可能已经被删除";
            throw new BusinessException(error);
        }
    }

    //TODO:---------------验证-------------------

    private void validateFindOrderMaterialRelations(PageDTO pageDTO) {
        //TODO:请使用下面方法添加数据过滤条件
        //		pageDTO.addFilter("creatorId",this.getLoginUserId());
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateFindOrderMaterialRelationsWithIdNameByName(String orderMaterialRelationName) {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }


    private void validateFindAllOrderMaterialRelationsWithIdName() {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateFindOrderMaterialRelationsWithIdNameById(Long orderMaterialRelationId) {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateFindOrderMaterialRelation(Long orderMaterialRelationId) {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateFindOrderMaterialRelationWithForeignName(Long orderMaterialRelationId) {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateSaveOrderMaterialRelation(OrderMaterialRelation orderMaterialRelation) {
        //不为空判断
        if (orderMaterialRelation.getEid() != null || orderMaterialRelation.getCreatorId() != null || orderMaterialRelation.getCreateDatetime() != null) {
            throw new BusinessException("非法请求");
        }
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateUpdateOrderMaterialRelation(OrderMaterialRelation orderMaterialRelation) {
        //不为空判断
        if (orderMaterialRelation.getEid() == null) {
            throw new BusinessException("唯一标识不能为空");
        }
        //是否存在判断
        if (this.orderMaterialRelationDao.findOrderMaterialRelationTotalCount(PageDTO.create(OrderMaterialRelation.FIELD_ID, orderMaterialRelation.getEid())) == 0) {
            throw new BusinessException("修改的订单材料关系 " + orderMaterialRelation.getName() + " 不存在，修改失败，请重试或联系管理员");
        }
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    private void validateDeleteOrderMaterialRelation(Long orderMaterialRelationId) {
        //TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateOrderMaterialRelation()写法
    }

    @Override
    public boolean canDownloadAttachment(String formName, Long id) {
        return true;
    }
}
